package manager;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import structures.log.LogData;
import util.HibernateUtil;
import domain.LogServiceCallDAO;
import domain.LogServiceCallDataDAO;
import domain.LogServiceCallErrorDAO;
import domain.LogServiceCallOutDAO;
import exception.IBToolsException;

@SuppressWarnings("unchecked")
public class LogManager {
	
	public static void logServiceCallSuccess(LogData data) throws IBToolsException {
		if(SessionManager.isLogging())
			logServiceCall(data, true);
	}

	public static void logServiceCallError(LogData data) throws IBToolsException {
		if(SessionManager.isLogging())
			logServiceCall(data, false);
	}

	private static void logServiceCall(LogData data, boolean success) throws IBToolsException {
		LogServiceCallDAO log = new LogServiceCallDAO();
		log.setServiceName(data.getCallInfo().getServiceName());
		log.setUserCode(data.getUserCode());
		DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
		log.setCallDatetime(dateFormat.format(new Date()));
		log.setCallDatetimestamp(new Date());
		log.setCallerIp(data.getClientIp());
		if(data.getCallInfo().isLocal())
			log.setTargetIp(data.getCallInfo().getTargetIp());
		log.setTargetServer(data.getCallInfo().getTargetServer());
		log.setEnvironment(data.getCallInfo().getEnvironment());
		log.setErrorType(data.getErrorType());
		log.setSuccess(success);

		log.setLogServiceCallDataList(xmlToLogParts(log, data.getCallInfo().getInXml()));
		
		if(success)
			log.setLogServiceCallOutList(xmlOutToLogParts(log, data.getCallInfo().getOutXml()));
		else
			log.setLogServiceCallErrorList(errorToLogParts(log, data.getErrorText()));
		
		persistLog(log);
		
	}
	
	private static Set<LogServiceCallDataDAO> xmlToLogParts(LogServiceCallDAO log, String xml){		
		int index = 1;
		Set<LogServiceCallDataDAO> logServiceCallDataList = new HashSet<LogServiceCallDataDAO>();

		while(xml.length() > 1000){
			LogServiceCallDataDAO logData = new LogServiceCallDataDAO();
			logData.setXmlString(xml.substring(0, 1000));
			logData.setPart(index);
			logData.setLogServiceCall(log);
			logServiceCallDataList.add(logData);
			xml = xml.substring(1000);
			index++;
		}
		if(xml.length() > 0){
			LogServiceCallDataDAO logData = new LogServiceCallDataDAO();
			logData.setXmlString(xml);
			logData.setPart(index);
			logData.setLogServiceCall(log);
			logServiceCallDataList.add(logData);
		}
		return logServiceCallDataList;
	}

	private static Set<LogServiceCallOutDAO> xmlOutToLogParts(LogServiceCallDAO log, String xml){	
		int index = 1;
		Set<LogServiceCallOutDAO> logServiceCallOutList = new HashSet<LogServiceCallOutDAO>();

		while(xml.length() > 1000){
			LogServiceCallOutDAO logData = new LogServiceCallOutDAO();
			logData.setXmlString(xml.substring(0, 1000));
			logData.setPart(index);
			logData.setLogServiceCall(log);
			logServiceCallOutList.add(logData);
			xml = xml.substring(1000);
			index++;
		}
		if(xml.length() > 0){
			LogServiceCallOutDAO logData = new LogServiceCallOutDAO();
			logData.setXmlString(xml);
			logData.setPart(index);
			logData.setLogServiceCall(log);
			logServiceCallOutList.add(logData);
		}
		return logServiceCallOutList;
	}
	
	private static Set<LogServiceCallErrorDAO> errorToLogParts(LogServiceCallDAO log, String errorText){
		String errorPart = errorText;
		int index = 1;
		
		Set<LogServiceCallErrorDAO> logServiceCallErrorList = new HashSet<LogServiceCallErrorDAO>();
		
		while(errorPart.length() > 100){
			LogServiceCallErrorDAO errorData = new LogServiceCallErrorDAO();
			errorData.setErrorText(errorPart.substring(0, 100));
			errorData.setPart(index);
			errorData.setLogServiceCall(log);
			logServiceCallErrorList.add(errorData);
			errorPart = errorPart.substring(100);
			index++;
		}
		if(errorPart.length() > 0){
			LogServiceCallErrorDAO errorData = new LogServiceCallErrorDAO();
			errorData.setErrorText(errorPart);
			errorData.setPart(index);
			errorData.setLogServiceCall(log);
			logServiceCallErrorList.add(errorData);
		}
		
		return logServiceCallErrorList;
	}
	
	private static Long persistLog(LogServiceCallDAO log) throws IBToolsException{
    	Session session = HibernateUtil.getDEVSession();
        Transaction tx = null;
        
        try {
			tx = HibernateUtil.beginDEVTransaction(session);
			session.saveOrUpdate(log);
			tx.commit();
		} catch (HibernateException e) {
			tx.rollback();
			throw e;
		}
        
        return log.getOid();
	}

	public static String loadServiceCallDataLog(LogServiceCallDAO log) throws IBToolsException {
		StringBuffer xml = new StringBuffer();
		
    	Session session = HibernateUtil.getDEVSession();
        Transaction tx = null;
        
        try {
			tx = HibernateUtil.beginDEVTransaction(session);
			List<LogServiceCallDataDAO> list = (List<LogServiceCallDataDAO>)session.createCriteria(LogServiceCallDataDAO.class)
					.add(Restrictions.eq("logServiceCall", log))
					.addOrder(Order.asc("part")).list();
			for (LogServiceCallDataDAO dataDAO : list) {
				xml.append(dataDAO.getXmlString());
			}
			tx.commit();
		} catch (HibernateException e) {
			tx.rollback();
			throw e;
		}
		return xml.toString();
	}
	
	public static String loadServiceCallOutLog(LogServiceCallDAO log, boolean sample) throws IBToolsException {
		StringBuffer xml = new StringBuffer();
		
    	Session session = HibernateUtil.getDEVSession();
        Transaction tx = null;
        
        try {
			tx = HibernateUtil.beginDEVTransaction(session);
			Criteria criteria = session.createCriteria(LogServiceCallOutDAO.class)
					.add(Restrictions.eq("logServiceCall", log))
					.addOrder(Order.asc("part"));
			if(sample){
				criteria.add(Restrictions.eq("part", 1));
			}
			List<LogServiceCallOutDAO> list = (List<LogServiceCallOutDAO>)criteria.list();
			for (LogServiceCallOutDAO dataDAO : list) {
				xml.append(dataDAO.getXmlString());
			}
			tx.commit();
		} catch (HibernateException e) {
			tx.rollback();
			throw e;
		}

	    
//		int currentPart = 1;
//		while(currentPart < log.getLogServiceCallOutList().size() + 1){
//			for (LogServiceCallOutDAO s : log.getLogServiceCallOutList()) {
//			    if(s.getPart() == currentPart){
//			    	xml.append(s.getXmlString());
//				    currentPart++;
//				    break;
//			    }
//			}
//			if(sample)
//				break;
//		}
        String xmlString = xml.toString();
        if(!xmlString.equalsIgnoreCase(""))
        	xmlString = xmlString.substring(xmlString.indexOf("<"));
		return xmlString;
	}
	
	public static String loadServiceCallErrorLog(LogServiceCallDAO log) throws IBToolsException {
		StringBuffer error = new StringBuffer();
		
    	Session session = HibernateUtil.getDEVSession();
        Transaction tx = null;
        
        try {
			tx = HibernateUtil.beginDEVTransaction(session);
			List<LogServiceCallErrorDAO> list = (List<LogServiceCallErrorDAO>)session.createCriteria(LogServiceCallErrorDAO.class)
					.add(Restrictions.eq("logServiceCall.oid", log.getOid()))
					.addOrder(Order.asc("part")).list();
			for (LogServiceCallErrorDAO errorDAO : list) {
				error.append(errorDAO.getErrorText());
			}
			tx.commit();
		} catch (HibernateException e) {
			tx.rollback();
			throw e;
		}
		return error.toString();
	}
}
